package com.dmgis.qxfw.dataservice.commonservice.dmgis_mongodb_srv.common.util;

import java.io.Serializable;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;


/**   
 * This class is used for 日期时间类  
 * @author dsq 
 * @version   
 *       1.0, 2018年7月2日 下午3:13:33   
 */  
public class DateTime implements Serializable {

	/**
	 * 
	 */
	private static final long serialVersionUID = 1L;
	/**
	 * yyyy-MM-dd HH:mm:ss 格式
	 */
	public static final String DEFAULT_DATE_TIME_FORMAT_PATTERN = "yyyy-MM-dd HH:mm:ss";
	/**
	 * yyyy-MM-dd HH:mm 格式
	 */
	public static final String DEFAULT_DATE_TIME_HHmm_FORMAT_PATTERN = "yyyy-MM-dd HH:mm";
	/**
	 * yyyy-MM-dd HH 格式
	 */
	public static final String DEFAULT_DATE_TIME_HH_FORMAT_PATTERN = "yyyy-MM-dd HH";
	/**
	 * yyyy-MM-dd 格式
	 */
	public static final String DEFAULT_DATE_FORMAT_PATTERN = "yyyy-MM-dd";
	/**
	 * HH:mm:ss 格式
	 */
	public static final String DEFAULT_TIME_FORMAT_PATTERN = "HH:mm:ss";
	/**
	 * HH:mm 格式
	 */
	public static final String DEFAULT_TIME_HHmm_FORMAT_PATTERN = "HH:mm";
	/**
	 * 年
	 * <p>
	 * 可以通过DateTime.now().get(DateTime.YEAR_FIELD)来获取当前时间的年
	 * </p>
	 */
	public static final int YEAR_FIELD = Calendar.YEAR;
	/**
	 * 月
	 * <p>
	 * 可以通过DateTime.now().get(DateTime.MONTH_FIELD)来获取当前时间的月
	 * </p>
	 */
	public static final int MONTH_FIELD = Calendar.MONTH;

	public static final int WEEK_FIELD = Calendar.DAY_OF_WEEK;
	/**
	 * 日
	 * <p>
	 * 可以通过DateTime.now().get(DateTime.DAY_FIELD)来获取当前时间的日
	 * </p>
	 */
	public static final int DAY_FIELD = Calendar.DATE;
	/**
	 * 小时
	 * <p>
	 * 可以通过DateTime.now().get(DateTime.HOUR_FIELD)来获取当前时间的小时
	 * </p>
	 */
	public static final int HOUR_FIELD = Calendar.HOUR_OF_DAY;
	/**
	 * 分钟
	 * <p>
	 * 可以通过DateTime.now().get(DateTime.MINUTE_FIELD)来获取当前时间的分钟
	 * </p>
	 */
	public static final int MINUTE_FIELD = Calendar.MINUTE;

	/**
	 * 秒
	 * <p>
	 * 可以通过DateTime.now().get(DateTime.SECOND_FIELD)来获取当前时间的秒
	 * </p>
	 */
	public static final int SECOND_FIELD = Calendar.SECOND;
	/**
	 * 毫秒
	 * <p>
	 * 可以通过DateTime.now().get(DateTime.MILLISECOND_FIELD)来获取当前时间的毫秒
	 * </p>
	 */
	public static final int MILLISECOND_FIELD = Calendar.MILLISECOND;
	private Calendar c; // 日历类

	/**
	 * 获取一个DateTime,此DateTime尚未初始化,表示的时间是1970-1-1 00:00:00.000
	 * <p>
	 * 要获取当前系统时间,请用DateTime.now();
	 * </p>
	 */
	public DateTime() {
		c = Calendar.getInstance();
		c.clear();
	}

	/**
	 * 设置时间
	 * <p>
	 * 可以传入一个时间对象，将会被转换为DateTime类型
	 * </p>
	 *
	 * @param date
	 *            时间对象
	 */
	public DateTime(Date date) {
		c = Calendar.getInstance();
		c.setTime(date);
	}

	/**
	 * 设置时间
	 * <p>
	 * 可以传入一个日历对象，将会被转换为DateTime类型
	 * </p>
	 *
	 * @param calendar
	 *            日历对象
	 */
	public DateTime(Calendar calendar) {
		this.c = calendar;
	}

	/**
	 * 获取当前系统时间
	 *
	 * @return DateTime 当前系统时间
	 */
	public static DateTime now() {
		Calendar calendar = Calendar.getInstance();
		return new DateTime(calendar);
	}

	/**
	 * 用毫秒来设置时间, 时间的基数是1970-1-1 00:00:00.000;
	 * <p>
	 * 比如,new DateTime(1000) 则表示1970-1-1 00:00:01.000;<br>
	 * 用负数表示基础时间以前的时间
	 * </p>
	 *
	 * @param milliseconds
	 *            毫秒
	 */
	public DateTime(long milliseconds) {
		c = Calendar.getInstance();
		c.setTimeInMillis(milliseconds);
	}

	/**
	 * 转换为Date类型
	 *
	 * @return Date时间
	 */
	public Date toDate() {
		return c.getTime();
	}

	/**
	 * 转换成 日历对象
	 *
	 * @return Calendar对象
	 */
	public Calendar toCalendar() {
		return c;
	}

	/**
	 * 转换成java.sql.Date(yyyy-MM-dd)日期
	 *
	 * @return java.sql.Date日期
	 */
	public java.sql.Date toSqlDate() {
		return new java.sql.Date(c.getTimeInMillis());
	}

	/**
	 * 转换为java.sql.Time(hh:mm:ss)时间
	 *
	 * @return java.sql.Time时间
	 */
	public java.sql.Time toSqlTime() {
		return new java.sql.Time(c.getTimeInMillis());
	}

	/**
	 * 转换为java.sql.Timestamp(时间戳)
	 *
	 * @return java.sql.Timestamp时间戳
	 */
	public java.sql.Timestamp toSqlTimestamp() {
		return new java.sql.Timestamp(c.getTimeInMillis());
	}

	/**
	 * 解析时间
	 * <p>
	 * 根据DateTime中的DEFAULT_TIME_FORMAT_PATTERN规则转换为hh:mm:ss或hh:mm格式
	 * </p>
	 *
	 * @param time
	 *            字符串格式时间
	 * @return DateTime 日期时间对象
	 */
	public static DateTime parseTime(String time) throws ParseException {
		try {
			return DateTime.parseDateTime(time, DateTime.DEFAULT_TIME_FORMAT_PATTERN);
		} catch (ParseException e) {
			return DateTime.parseDateTime(time, DateTime.DEFAULT_TIME_HHmm_FORMAT_PATTERN);
		}
	}

	/**
	 * 解析日期
	 * <p>
	 * 根据DateTime中的DEFAULT_DATE_FORMAT_PATTERN规则转换为yyyy-MM-dd格式
	 * </p>
	 *
	 * @param date
	 *            字符串格式日期
	 * @return DateTime 日期时间类
	 */
	public static DateTime parseDate(String date) throws ParseException {
		return DateTime.parseDateTime(date, DateTime.DEFAULT_DATE_FORMAT_PATTERN);
	}

	/**
	 * 解析日期时间
	 * <p>
	 * 根据DateTime中的DEFAULT_DATE_TIME_FORMAT_PATTERN规则转换为yyyy-MM-dd HH:mm:ss格式
	 * </p>
	 *
	 * @param datetime
	 *            字符串格式日期时间
	 * @return DateTime 日期时间对象
	 */
	public static DateTime parseDateTime(String datetime) throws ParseException {
		DateTime result = null;
		// 尝试按yyyy-MM-dd HH:mm:ss分析
		try {
			result = DateTime.parseDateTime(datetime, DateTime.DEFAULT_DATE_TIME_FORMAT_PATTERN);
		} catch (ParseException e) {
			// 解析错误
			result = null;
		}

		// 尝试按yyyy-MM-dd HH:mm分析
		if (null == result) {
			try {
				result = DateTime.parseDateTime(datetime, DateTime.DEFAULT_DATE_TIME_HHmm_FORMAT_PATTERN);
			} catch (ParseException e) {
				// 解析错误
				result = null;
			}
		}

		// 尝试按yyyy-MM-dd HH分析
		if (null == result) {
			try {
				result = DateTime.parseDateTime(datetime, DateTime.DEFAULT_DATE_TIME_HH_FORMAT_PATTERN);
			} catch (ParseException e) {
				// 解析错误
				result = null;
			}
		}

		// 尝试按yyyy-MM-dd分析
		if (null == result) {
			try {
				result = DateTime.parseDate(datetime);
			} catch (ParseException e) {
				// 解析错误
				result = null;
			}
		}

		// 尝试按时间分析
		if (null == result) {
			result = DateTime.parseTime(datetime);
		}
		return result;
	}

	/**
	 * 用指定的pattern分析字符串
	 * <p>
	 * pattern的用法参见java.text.SimpleDateFormat
	 * </p>
	 *
	 * @param datetime
	 *            字符串格式日期时间
	 * @param pattern
	 *            日期解析规则
	 * @return DateTime 日期时间对象
	 * @see SimpleDateFormat
	 */
	public static DateTime parseDateTime(String datetime, String pattern) throws ParseException {
		SimpleDateFormat fmt = (SimpleDateFormat) DateFormat.getDateInstance();
		fmt.applyPattern(pattern);
		return new DateTime(fmt.parse(datetime));
	}

	/**
	 * 转换为 DEFAULT_DATE_FORMAT_PATTERN (yyyy-MM-dd) 格式字符串
	 *
	 * @return yyyy-MM-dd格式字符串
	 */
	public String toDateString() {
		return toDateTimeString(DateTime.DEFAULT_DATE_FORMAT_PATTERN);
	}

	/**
	 * 转换为 DEFAULT_TIME_FORMAT_PATTERN (HH:mm:ss) 格式字符串
	 *
	 * @return HH:mm:ss 格式字符串
	 */
	public String toTimeString() {
		return toDateTimeString(DateTime.DEFAULT_TIME_FORMAT_PATTERN);
	}

	/**
	 * 转换为 DEFAULT_DATE_TIME_FORMAT_PATTERN (yyyy-MM-dd HH:mm:ss) 格式字符串
	 *
	 * @return yyyy-MM-dd HH:mm:ss 格式字符串
	 */
	public String toDateTimeString() {
		return toDateTimeString(DateTime.DEFAULT_DATE_TIME_FORMAT_PATTERN);
	}

	/**
	 * 使用日期转换pattern
	 * <p>
	 * pattern的用法参见java.text.SimpleDateFormat
	 * </p>
	 *
	 * @param pattern
	 *            日期解析规则
	 * @return 按规则转换后的日期时间字符串
	 */
	public String toDateTimeString(String pattern) {
		SimpleDateFormat fmt = (SimpleDateFormat) DateFormat.getDateInstance();
		fmt.applyPattern(pattern);
		return fmt.format(c.getTime());
	}

	/**
	 * @return 年份
	 * @author dsq
	 * @date 2018年6月28日
	 */
	public int GetYear() {
		return c.get(YEAR_FIELD);
	}

	/**
	 * @return 月份
	 * @author dsq
	 * @date 2018年6月28日
	 */
	public int GetMonth() {
		return c.get(MONTH_FIELD) + 1;
	}

	/**
	 * 获取日
	 *
	 * @return
	 * @author dsq
	 * @date 2018年6月28日
	 */
	public int GetDay() {
		return c.get(DAY_FIELD);
	}

	/**
	 * 获取小时
	 *
	 * @return
	 * @author dsq
	 * @date 2018年6月28日
	 */
	public int GetHour() {
		return c.get(HOUR_FIELD);
	}

	/**
	 * 获取分钟
	 *
	 * @return
	 * @author dsq
	 * @date 2018年6月28日
	 */
	public int GetMinute() {
		return c.get(MINUTE_FIELD);
	}

	/**
	 * 获取秒
	 *
	 * @return
	 * @author dsq
	 * @date 2018年6月28日
	 */
	public int GetSecond() {
		return c.get(SECOND_FIELD);
	}

	/**
	 * 获取毫秒
	 *
	 * @return
	 * @author dsq
	 * @date 2018年6月28日
	 */
	public int GetMillSecond() {
		return c.get(MILLISECOND_FIELD);
	}

	/**
	 * 从星期天开始，下标为1
	 *
	 * @return
	 * @author dsq
	 * @date 2018年6月29日
	 */
	public int GetWeek() {
		return c.get(WEEK_FIELD);
	}

	/**
	 * 返回中文类型的星期
	 *
	 * @return
	 * @author dsq
	 * @date 2018年6月29日
	 */
	public String getweString() {
		String[] weekDays = { "星期日", "星期一", "星期二", "星期三", "星期四", "星期五", "星期六" };
		return weekDays[c.get(WEEK_FIELD) - 1];
	}

	/**
	 * 返回自 1970-1-1 0:0:0 至此时间的毫秒数
	 *
	 * @return long 毫秒数
	 */
	public long GetTimeInMillis() {
		return c.getTimeInMillis();
	}

	/**
	 * 设置field字段的值
	 *
	 * @param field
	 *            int 取值为:<br>
	 *            DateTime.YEAR_FIELD -- 年份<br>
	 *            DateTime.MONTH_FIELD -- 月份,一月份从1开始<br>
	 *            DateTime.DAY_FIELD -- 当前的天(本月中的)<br>
	 *            DateTime.HOUR_FIELD -- 小时数(本天中的),24小时制<br>
	 *            DateTime.MINUTE_FIELD -- 分钟数(本小时中的)<br>
	 *            DateTime.SECOND_FIELD -- 秒数(本分钟中的)<br>
	 *            DateTime.MILLISECOND_FIELD -- 毫秒数(本秒中的)
	 * @param value
	 */
	public DateTime set(int field, int value) {
		// 月份需要-1(月份从0开始)
		if (DateTime.MONTH_FIELD == field) {
			c.set(field, value - 1);
		} else {
			c.set(field, value);
		}
		return this;
	}

	/**
	 * 设置DateTime日期的年/月/日
	 *
	 * @param year
	 *            年
	 * @param month
	 *            月
	 * @param day
	 *            日
	 */
	public DateTime set(int year, int month, int day) {
		set(DateTime.YEAR_FIELD, year);
		set(DateTime.MONTH_FIELD, month);
		set(DateTime.DAY_FIELD, day);
		return this;
	}

	/**
	 * 设置DateTime日期的年/月/日/小时
	 *
	 * @param year
	 *            年
	 * @param month
	 *            月
	 * @param day
	 *            日
	 * @param hour
	 *            小时
	 */
	public DateTime set(int year, int month, int day, int hour) {
		set(year, month, day);
		set(DateTime.HOUR_FIELD, hour);
		return this;
	}

	/**
	 * 设置DateTime日期的年/月/日/小时/分钟
	 *
	 * @param year
	 *            年
	 * @param month
	 *            月
	 * @param day
	 *            日
	 * @param hour
	 *            小时
	 * @param minute
	 *            分钟
	 */
	public DateTime set(int year, int month, int day, int hour, int minute) {
		set(year, month, day, hour);
		set(DateTime.MINUTE_FIELD, minute);
		return this;
	}

	/**
	 * 设置DateTime日期的年/月/日/小时/分钟/秒
	 *
	 * @param year
	 *            年
	 * @param month
	 *            月
	 * @param day
	 *            日
	 * @param hour
	 *            小时
	 * @param minute
	 *            分钟
	 * @param second
	 *            秒
	 */
	public DateTime set(int year, int month, int day, int hour, int minute, int second) {
		set(year, month, day, hour, minute);
		set(DateTime.SECOND_FIELD, second);
		return this;
	}

	/**
	 * 设置DateTime日期的年/月/日/小时/分钟/秒/毫秒
	 *
	 * @param year
	 *            年
	 * @param month
	 *            月
	 * @param day
	 *            日
	 * @param hour
	 *            小时
	 * @param minute
	 *            分钟
	 * @param second
	 *            秒
	 * @param milliSecond
	 *            毫秒
	 */
	public DateTime set(int year, int month, int day, int hour, int minute, int second, int milliSecond) {
		set(year, month, day, hour, minute, second);
		set(DateTime.MILLISECOND_FIELD, milliSecond);
		return this;
	}

	/**
	 * 返回一个新的 System.DateTime，它将指定的天数加到此实例的值上。
	 *
	 * @param value
	 * @return
	 * @author dsq
	 * @date 2018年6月28日
	 */
	public DateTime AddDays(int value) {
		Calendar c = (Calendar) this.c.clone();
		c.add(DAY_FIELD, value);
		return (DateTime) new DateTime(c).clone();
	}

	/**
	 * 返回一个新的 System.DateTime，它将指定的时间加到此实例的值上
	 *
	 * @param value
	 * @return
	 * @author dsq
	 * @date 2018年6月28日
	 */
	public DateTime AddHours(int value) {
		Calendar c = (Calendar) this.c.clone();
		c.add(HOUR_FIELD, value);
		return (DateTime) new DateTime(c).clone();
	}

	/**
	 * 返回一个新的 System.DateTime，它将指定的毫秒数加到此实例的值上。
	 *
	 * @param value
	 * @return
	 * @author dsq
	 * @date 2018年6月28日
	 */
	public DateTime AddMilliseconds(int value) {
		Calendar c = (Calendar) this.c.clone();
		c.add(MILLISECOND_FIELD, value);
		return (DateTime) new DateTime(c).clone();
	}

	/**
	 * 返回一个新的 System.DateTime，它将指定的分钟数加到此实例的值上。
	 *
	 * @param value
	 * @return
	 * @author dsq
	 * @date 2018年6月28日
	 */
	public DateTime AddMinutes(int value) {
		Calendar c = (Calendar) this.c.clone();
		c.add(MINUTE_FIELD, value);
		return (DateTime) new DateTime(c).clone();
	}

	/**
	 * 返回一个新的 System.DateTime，它将指定的月数加到此实例的值上。
	 *
	 * @param value
	 * @return
	 * @author dsq
	 * @date 2018年6月28日
	 */
	public DateTime AddMonths(int value) {
		Calendar c = (Calendar) this.c.clone();
		c.add(MONTH_FIELD, value);
		return (DateTime) new DateTime(c).clone();
	}

	/**
	 * 返回一个新的 System.DateTime，它将指定的秒数加到此实例的值上。
	 *
	 * @param value
	 * @return
	 * @author dsq
	 * @date 2018年6月28日
	 */
	public DateTime AddSeconds(int value) {
		Calendar c = (Calendar) this.c.clone();
		c.add(SECOND_FIELD, value);
		return (DateTime) new DateTime(c).clone();
	}

	/**
	 * 返回一个新的 System.DateTime，它将指定的月数加到此实例的值上。
	 *
	 * @param value
	 * @return
	 * @author dsq
	 * @date 2018年6月28日
	 */
	public DateTime AddYears(int value) {
		Calendar c = (Calendar) this.c.clone();
		c.add(YEAR_FIELD, value);
		return (DateTime) new DateTime(c).clone();
	}

	/**
	 * 判断此 DateTime 表示的时间是否在指定 Object 表示的时间之后，返回判断结果。
	 * <p>
	 * 此方法等效于：compareTo(when) > 0<br>
	 * 当且仅当 when 是一个 DateTime 实例时才返回 true。否则该方法返回 false。
	 *
	 * @param when
	 *            要比较的 Object
	 * @return 如果此 DateTime 的时间在 when 表示的时间之后，则返回 true；否则返回 false。
	 */
	public boolean after(Object when) {
		if (when instanceof DateTime) {
			return c.after(((DateTime) when).c);
		}
		return c.after(when);
	}

	/**
	 * 判断此 DateTime 表示的时间是否在指定 Object 表示的时间之前，返回判断结果。
	 * <p>
	 * 此方法等效于：compareTo(when) < 0<br>
	 * 当且仅当 when 是一个 DateTime 实例时才返回 true。否则该方法返回 false。
	 * </p>
	 *
	 * @param when
	 *            要比较的 Object
	 * @return 如果此 Calendar 的时间在 when 表示的时间之前，则返回 true；否则返回 false。
	 */
	public boolean before(Object when) {
		if (when instanceof DateTime) {
			return c.before(((DateTime) when).c);
		}
		return c.before(when);
	}

	/**
	 * 是否用主表
	 *
	 * @param date
	 * @param cacheDays
	 * @return
	 * @author dsq
	 * @date 2018年6月30日
	 */
	public static boolean UserMainDataTable(Date date, int cacheDays) {

		return new DateTime(date).AddDays(cacheDays).before(DateTime.now());
	}

	/**
	 * 根据毫秒数获取两个日期相差的年、月、日
	 *
	 * @param startDate
	 * @param endDate
	 * @param field
	 *            年、月、日
	 * @return
	 * @author dsq
	 * @date 2018年7月2日
	 */
	public static int getDiffByMillisecond(DateTime startDate, DateTime endDate, int field) {
		int unit = 1;
		if (field == DAY_FIELD) {
			unit = 1000 * 60 * 60 * 24;
		}
		if (field == HOUR_FIELD) {
			unit = 1000 * 60 * 60;
		}
		if (field == MINUTE_FIELD) {
			unit = 1000 * 60;
		}
		if (field == SECOND_FIELD) {
			unit = 1000;
		}
		return (int) (endDate.GetTimeInMillis() - startDate.GetTimeInMillis()) / unit;
	}

	/**
	 * 创建并返回此对象的一个副本
	 *
	 * @return 日期时间对象
	 */
	@Override
	public Object clone() {
		return new DateTime((Calendar) c.clone());
	}

	/**
	 * 返回该此日历的哈希码
	 *
	 * @return 此对象的哈希码值。
	 * @see Object
	 */
	@Override
	public int hashCode() {
		return c.hashCode();
	}

	/**
	 * 将此 DateTime 与指定 Object 比较。
	 *
	 * @param obj
	 *            - 要与之比较的对象。
	 * @return 如果此对象等于 obj，则返回 true；否则返回 false。
	 * @see Object
	 */
	@Override
	public boolean equals(Object obj) {
		if (obj instanceof DateTime) {
			return c.equals(((DateTime) obj).toCalendar());
		}
		if (obj instanceof Calendar) {
			return c.equals(obj);
		}
		if (obj instanceof Date) {
			return c.getTime().equals(obj);
		}
		return false;
	}
}
